﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;
using SimpleRest.Core.Routing;

namespace SimpleRest.Core
{
    /// <summary>
    /// Used to assist in service registration.  To easily register services you may use this class and in doing so be given
    /// event handling for services that get registered.
    /// </summary>
    public static class ServiceDiscoveryFactory
    {
        static ServiceDiscoveryFactory()
        {
        }

        static void ServiceHelper_ServiceRegistered(ServiceRegisteredEventArgs e)
        {
        }

        /// <summary>
        /// Register service of type T with associated service configuration setup.
        /// </summary>
        /// <typeparam name="T">Must be a type that is attributed with ServiceAttribute.</typeparam>
        /// <param name="configuration">Service configuration that drives behavior of the registered service type.</param>
        /// <returns></returns>
        public static ServiceRoute RegisterService<T>(Configuration configuration)
        {
            if (configuration == null)
                throw new Exception("Please specify a configuration for service route registration.");

            return RegisterService(typeof(T), configuration);
        }

        /// <summary>
        /// Register service of type T with associated service configuration setup.
        /// </summary>
        /// <param name="type">Must be a type that is attributed with ServiceAttribute.</param>
        /// <param name="configuration">Service configuration that drives behavior of the registered service type.</param>
        /// <returns></returns>
        public static ServiceRoute RegisterService(Type type, Configuration configuration)
        {
            if (configuration == null)
                throw new Exception("Please specify a configuration for service route registration.");

            string version = "";
            var attribute = type.GetCustomAttributes(true).FirstOrDefault(d => d.GetType().FullName == typeof(ServiceAttribute).FullName) as ServiceAttribute;

            if (attribute != null)
            {
                version = attribute.GetVersion();
            }
            else
                throw new Exception("Attempt to register service " + type.FullName + " without a version attribute.  Please make sure you have a Version attribute on the service you are attempting to register.");


            var route = new ServiceRoute(type, configuration);
            RouteUtility.Routes.Add(route);
            return route;
        }

        /// <summary>
        /// Scan list of assembilies and register all services adorned with ServiceAttribute against the associated service configuration object
        /// specified in the input parameter.
        /// </summary>
        /// <param name="configuration">Service configuration that will be registered with all services found in any associated assembilies.</param>
        /// <param name="assembilies">A list of assembilies which will be scanned for valid services.</param>
        public static void ScanAndRegisterServices(Configuration configuration, params System.Reflection.Assembly[] assembilies)
        {
            if (configuration == null)
                throw new Exception("Please specify a configuration for service route registration.");

            if (assembilies == null)
                assembilies = new System.Reflection.Assembly[] { System.Reflection.Assembly.GetExecutingAssembly() };

            foreach (var assembly in assembilies)
            {
                foreach (Type type in assembly.GetTypes())
                {
                    if (!type.IsAbstract)
                    {
                        ServiceAttribute attribute =
                            type.GetCustomAttributes(true).FirstOrDefault(d => d.GetType().FullName == typeof(ServiceAttribute).FullName) as ServiceAttribute;

                        if (attribute != null)
                        {
                            var route = RegisterService(type, configuration);
                        }
                    }
                }
            }
        }
    }
}
